// +-------------------------------- DISCLAIMER ---------------------------------+
// |                                                                             |
// | This program is provided to you free of charge "as such".                   |
// | You should not assume that this program is error-free or suitable for any   |
// | purpose whatsoever.                                                         |
// |                                                                             |
// | EURESYS does not give any representation, warranty or undertaking that this |
// | program is free of any defect or error or suitable for any purpose. EURESYS |
// | shall not be liable, in contract, in torts or otherwise, for any damages,   |
// | loss, costs, expenses or other claims for compensation, including those     |
// | asserted by third parties, arising out of or in connection with the use of  |
// | this program.                                                               |
// +-----------------------------------------------------------------------------+

#include "CameraHandler.h"
#include <QPainter>
#include "QtDrawAdapter.h"

#include "ProcessingHandler.h"

// Choose one processing in BarCode, MatrixCode or QRCode
#define BarCodeProcessing
//#define MatrixCodeProcessing
//#define QRCodeProcessing


#if defined(BarCodeProcessing)
#include "EasyBarCode.h"
#elif defined(MatrixCodeProcessing)
#include "EasyMatrixCode.h"
#elif defined(QRCodeProcessing)
#include "EasyQRCode.h"
#else
#error "Unknown processing"
#endif

using namespace Euresys::Open_eVision;


ProcessingHandler::ProcessingHandler(CameraHandler* cameraHandler) : abort_(false), cameraHandler_(cameraHandler)
{
}

ProcessingHandler::~ProcessingHandler()
{
  if (processingThread_.joinable())
  {
    abort_ = true;
    // waits for ProcessingHandler::run to end

    processingThread_.join();
  }
  std::cout << "Destroyed ProcessingHandler" << std::endl;
}

void ProcessingHandler::start()
{
  // run main loop in a separate thread
  processingThread_ = std::thread(&ProcessingHandler::run, this);
}

void ProcessingHandler::stop()
{
  abort_ = false;
}

bool ProcessingHandler::isAborted()
{
  return abort_;
}

void ProcessingHandler::run()
{
  try
  {
    // declare and initialize the right code reader
#if defined(BarCodeProcessing)
    EasyBarCode2::EBarCodeReader reader;
    reader.SetMaxNumCodes(1);
    std::vector<EasyBarCode2::EBarCode> results;
#elif defined(MatrixCodeProcessing)
    EasyMatrixCode2::EMatrixCodeReader reader;
    reader.SetMaxNumCodes(1);
    std::vector<EasyMatrixCode2::EMatrixCode> results;
#elif defined(QRCodeProcessing)
    EQRCodeReader reader;
    std::vector<EQRCode> results;
#else
#error "Unknow processing"
#endif

    EImageBW8 src;

    constexpr float zoom = 1.f;

    while(!abort_)
    {
      cameraHandler_->getImage(src);

      // find and read the code
      results.clear();
#if defined(BarCodeProcessing) || defined(QRCodeProcessing)
      results = reader.Read(src);
#elif defined(MatrixCodeProcessing)
      try
      {
        reader.Read(src);
        results = reader.GetReadResults();
      }
      catch(const EException& exc)
      {
        // ignored because matrix code processing can throw exceptions
        // as part of its normal processing
      }
#endif

      // get the result string
      std::string decodedString = "";
      if (results.empty())
      {
        std::cout << "Could not find a code" << std::endl;
      }
      else
      {
#if defined(BarCodeProcessing) || defined(MatrixCodeProcessing)
        decodedString = results[0].GetDecodedString();
#elif defined(QRCodeProcessing)
        decodedString = results[0].GetDecodedString(EByteInterpretationMode_Auto);
#endif
        std::cout << decodedString << std::endl;
      }

      // draw the image with overlay
      QImage image(src.GetWidth(), src.GetHeight(), QImage::Format_RGB32);
      QPainter painter(&image);

      QtDrawAdapter drawAdapter(&painter);

      ERGBColor color = ERGBColor(0, 255, 255);
      EPen mypen(color, 5, EPenStyle_Solid);

      drawAdapter.SetPen(mypen);

      src.Draw(&drawAdapter, zoom, zoom, 0, 0);

      if (!results.empty())
      {
#if defined(BarCodeProcessing) || defined(MatrixCodeProcessing)
        results[0].DrawPosition(&drawAdapter, zoom, zoom, 0, 0);
#elif defined(QRCodeProcessing)
        results[0].GetGeometry().GetPosition().Draw(&drawAdapter, zoom, zoom, 0, 0);
#endif
      }

      Q_EMIT renderedImage(image, QString::fromStdString(decodedString));

    }
  }
  catch (EException e)
  {
    std::cerr << "OeV exception caught: " << e.what() << std::endl;
    abort_ = true;
  }
}
